/* 
 * File:   Simulation.h
 * Author: cjjonker
 *
 * Created on 20 december 2012, 15:04
 */

#ifndef SIMULATION_H
#define	SIMULATION_H

#include <rfftw.h>             //the numerical simulation FFTW librar
#include <math.h>               //for various math functions
#include "Vector.h"
#include "Dataset.h"
#include "ScalarDataset.h"
#include "VectorDataset.h"
#include "VectorToScalarDataset.h"
#include "GradientDataset.h"

class Simulation {
    
    ScalarDataset* data_rho;
    VectorToScalarDataset* data_v;
    VectorToScalarDataset* data_f;
    
    VectorToScalarDataset* data_grad_v;
    VectorToScalarDataset* data_grad_rho;
    
    VectorToScalarDataset* data_v_angle;
    VectorToScalarDataset* data_f_angle;
    
    VectorToScalarDataset* data_grad_v_angle;
    VectorToScalarDataset* data_grad_rho_angle;   
    
    GradientDataset* vdata_grad_rho;    
    GradientDataset* vdata_grad_v;
    VectorDataset* vdata_v;
    VectorDataset* vdata_f;
    
public:

    
    static const int DIM = 50;				//size of simulation grid

    Simulation();
    virtual ~Simulation();
    void do_one_simulation_step();
    void init_simulation(size_t n, size_t b);		
    void insert_force(int X, int Y, double dx, double dy);
    void set_forces();

    void freeze();
    void unfreeze();
    void toggle_frozen();
    bool frozen;               //toggles on/off the animation

    void change_timestep(double change);
    void scale_viscosity(float scale);
    
    ScalarDataset* getRhoDataset() const;
    VectorToScalarDataset* getVDataset() const;
    VectorToScalarDataset* getFDataset() const;
    
    VectorToScalarDataset* getGradRhoDataset() const;
    VectorToScalarDataset* getGradVDataset() const;
    
    VectorToScalarDataset* getVAngleDataset() const;
    VectorToScalarDataset* getFAngleDataset() const;
    
    VectorToScalarDataset* getGradRhoAngleDataset() const;
    VectorToScalarDataset* getGradVAngleDataset() const;
    
    VectorDataset* getGradRhoVectorDataset() const;
    VectorDataset* getGradVVectorDataset() const;
    
    VectorDataset* getVVectorDataset() const;
    VectorDataset* getFVectorDataset() const;
    
    
    
    int getDim() const;
    Vector2f getVelocity(int idx) const;
    Vector2f getForce(int idx) const;
    
private:
    void FFT(int direction, void* vx);		
    void solve();
    void diffuse_matter();
    void update_buffers();
    //--- SIMULATION PARAMETERS ------------------------------------------------------------------------

    double dt;				//simulation time step
    float visc;				//fluid viscosity
    size_t dim, grid_dim;

    size_t bufferlength;

    fftw_real *vx, *vy;             //(vx,vy)   = velocity field at the current moment
    fftw_real *vx0, *vy0;           //(vx0,vy0) = velocity field at the previous moment
    fftw_real *fx, *fy;	            //(fx,fy)   = user-controlled simulation forces, steered with the mouse
    fftw_real *rho, *rho0;			//smoke density at the current (rho) and previous (rho0) moment
    rfftwnd_plan plan_rc, plan_cr;  //simulation domain discretization
    fftw_real **buffer_vx;
    fftw_real **buffer_vy;  
    fftw_real **buffer_fx;
    fftw_real **buffer_fy;
    fftw_real **buffer_rho;
};


inline int Simulation::getDim() const { return Simulation::DIM; }

inline Vector2f Simulation::getVelocity(int idx) const { return Vector2f(vx[idx], vy[idx]); }

inline Vector2f Simulation::getForce(int idx) const { return Vector2f(fx[idx], fy[idx]); }

inline ScalarDataset* Simulation::getRhoDataset() const { return data_rho; } 

inline VectorToScalarDataset* Simulation::getVDataset() const { return data_v; }

inline VectorToScalarDataset* Simulation::getFDataset() const { return data_f; }

inline VectorDataset* Simulation::getVVectorDataset() const { return vdata_v; }

inline VectorDataset* Simulation::getFVectorDataset() const { return vdata_f; }

inline VectorDataset* Simulation::getGradRhoVectorDataset() const {return vdata_grad_rho; }

inline VectorDataset* Simulation::getGradVVectorDataset() const {return vdata_grad_v; }

inline VectorToScalarDataset* Simulation::getGradRhoDataset() const { return data_grad_rho; }

inline VectorToScalarDataset* Simulation::getGradVDataset() const { return data_grad_v; }

inline VectorToScalarDataset* Simulation::getVAngleDataset() const { return data_v_angle; }

inline VectorToScalarDataset* Simulation::getFAngleDataset() const { return data_f_angle; }

inline VectorToScalarDataset* Simulation::getGradRhoAngleDataset() const { return data_grad_rho_angle; }

inline VectorToScalarDataset* Simulation::getGradVAngleDataset() const { return data_grad_v_angle; }

#endif	/* SIMULATION_H */

